package com.kongjs.application.controller.rest;

import com.kongjs.application.annotation.OperationLogging;
import com.kongjs.application.convert.MenusConverter;
import com.kongjs.application.enums.OperationName;
import com.kongjs.application.enums.OperationType;
import com.kongjs.application.model.dto.MenuExistsDTO;
import com.kongjs.application.model.dto.QueryMenuDTO;
import com.kongjs.application.model.dto.SaveMenuDTO;
import com.kongjs.application.model.dto.UpdateMenuDTO;
import com.kongjs.application.model.vo.*;
import com.kongjs.application.service.IMenusService;
import com.kongjs.application.util.MenuTreeBuilder;
import com.kongjs.common.rest.annotation.Rest;
import jakarta.annotation.Resource;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;


@Rest
@RestController
@RequestMapping("/menus")
public class MenusController {
    @Resource
    private MenusConverter menusConverter;
    @Resource
    private IMenusService menusService;

    @PreAuthorize("hasAuthority('api:menu:save:one')")
    @PostMapping
    @OperationLogging(operationName = OperationName.MENU, operationType = OperationType.SAVE_ONE)
    public boolean save(@RequestBody @Validated SaveMenuVO vo) {
        SaveMenuDTO dto = menusConverter.toDto(vo);
        BeanMap map = BeanMap.create(vo.getMeta());
        dto.setMeta(map);
        if (!ObjectUtils.isEmpty(vo.getSort())) {
            dto.setMenuSort(vo.getSort());
        }
        if (!ObjectUtils.isEmpty(vo.getMeta().getOrder())) {
            dto.setMenuSort(vo.getMeta().getOrder());
        }
        return menusService.save(dto);
    }

    @PreAuthorize("hasAuthority('api:menu:remove:one')")
    @DeleteMapping("/{id}")
    @OperationLogging(operationName = OperationName.MENU, operationType = OperationType.REMOVE_ONE)
    public boolean remove(@PathVariable("id") Long id) {
        return menusService.remove(id);
    }

    @PreAuthorize("hasAuthority('api:menu:update:one')")
    @PutMapping("/{id}")
    @OperationLogging(operationName = OperationName.MENU, operationType = OperationType.UPDATE_ONE)
    public boolean update(@PathVariable("id") Long id, @RequestBody @Validated UpdateMenuVO vo) {
        UpdateMenuDTO dto = menusConverter.toDto(vo);
        dto.setMeta(vo.getMeta());
        dto.setId(id);
        if (!ObjectUtils.isEmpty(vo.getSort())) {
            dto.setMenuSort(vo.getSort());
        }
        if (!ObjectUtils.isEmpty(vo.getMeta()) && !ObjectUtils.isEmpty(vo.getMeta().getOrder())) {
            dto.setMenuSort(vo.getMeta().getOrder());
        }
        return menusService.update(dto);
    }

    @PreAuthorize("hasAuthority('api:menu:update:one')")
    @PatchMapping("/{id}")
    @OperationLogging(operationName = OperationName.MENU, operationType = OperationType.UPDATE_ONE)
    public boolean updatePart(@PathVariable("id") Long id, @RequestBody UpdateMenuVO vo) {
        UpdateMenuDTO dto = menusConverter.toDto(vo);
        dto.setMeta(vo.getMeta());
        dto.setId(id);
        if (!ObjectUtils.isEmpty(vo.getSort())) {
            dto.setMenuSort(vo.getSort());
        }
        if (!ObjectUtils.isEmpty(vo.getMeta()) && !ObjectUtils.isEmpty(vo.getMeta().getOrder())) {
            dto.setMenuSort(vo.getMeta().getOrder());
        }
        return menusService.update(dto);
    }

    @GetMapping("/{id}")
    @OperationLogging(operationName = OperationName.MENU, operationType = OperationType.QUERY_ONE,recordResponse = false)
    public QueryMenuVO query(@PathVariable("id") Long id) {
        return null;
    }


    @PreAuthorize("hasAuthority('api:menu:query:list')")
    @GetMapping
    @OperationLogging(operationName = OperationName.MENU, operationType = OperationType.QUERY_LIST,recordResponse = false)
    public List<QueryMenuVO> list() {
        List<QueryMenuDTO> dtos = menusService.queryList();
        List<QueryMenuVO> vos = dtos.stream()
                .map(dto -> {
                    QueryMenuVO vo = menusConverter.toVo(dto);
                    QueryMenuMetaVO metaVO = menusConverter.toVo(dto.getMeta());
                    vo.setMeta(metaVO);
                    return vo;
                })
                .toList();
        return MenuTreeBuilder.buildTree(vos);
    }

    @PreAuthorize("hasAuthority('api:menu:query:list') || hasAuthority('api:menu:query:list')")
    @GetMapping("/trees")
    @OperationLogging(operationName = OperationName.MENU, operationType = OperationType.QUERY_TREE,recordResponse = false)
    public List<QueryMenuVO> trees() {
        List<QueryMenuDTO> dtos = menusService.trees();
        List<QueryMenuVO> vos = dtos.stream()
                .map(dto -> {
                    QueryMenuVO vo = menusConverter.toVo(dto);
                    QueryMenuMetaVO metaVO = menusConverter.toVo(dto.getMeta());
                    vo.setMeta(metaVO);
                    return vo;
                })
                .toList();
        return MenuTreeBuilder.buildTree(vos);
    }

    @PreAuthorize("hasAuthority('api:menu:save:one') || hasAuthority('api:menu:update:one') || hasAuthority('api:menu:query:exists')")
    @GetMapping("/exists")
    public Boolean exists(MenuExistsVO vo) {
        if (ObjectUtils.isEmpty(vo.getId()) && !StringUtils.hasText(vo.getName()) && !StringUtils.hasText(vo.getPath())) {
            return false;
        }
        MenuExistsDTO dto = new MenuExistsDTO();
        dto.setId(vo.getId());
        dto.setMenuName(vo.getName());
        dto.setMenuPath(vo.getPath());
        return menusService.exists(dto);
    }

    @GetMapping("/page")
    @OperationLogging(operationName = OperationName.MENU, operationType = OperationType.QUERY_PAGE,recordResponse = false)
    public PageVO<QueryMenuVO> page(@Validated PageQueryVO param) {
        return null;
    }

}
